/*
 * 简单向量实现: 向量长度,线性运算(+,-,数乘,数除), 内积(点乘)
 * 固定大小向量
 *
 * 历史:
 *	2019-12-15 姚彧 创建
 *  2019-12-16 ...  加入名字空间yy::math::
 *                  使用vs2019进行文件格式化
 * 					(x,y,z,w)初始化
 */

#ifndef _YY_FVECTOR_H_
#define _YY_FVECTOR_H_

#define FVECTOR FVector<n,Real>
#define FVECTOR_TEMPLATE template<int n, class Real>

#include <cmath>
#include <cstring>
#include <initializer_list>
#include <algorithm>

namespace yy
{
	namespace math
	{
		FVECTOR_TEMPLATE
			struct FVector
		{
			Real v[n];
			int _n() const { return n; }
			Real length() const { return sqrt(Dot(*this, *this)); }
			Real length2() const { return Dot(*this, *this); }

			FVector() { makeZero(); }
			FVector(Real x, Real y) { makeZero(); v[0] = x; v[1] = y; }
			FVector(Real x, Real y, Real z) { makeZero(); v[0] = x; v[1] = y; v[2] = z; }
			FVector(Real x, Real y, Real z, Real w) { makeZero(); v[0] = x; v[1] = y; v[2] = z; v[3] = w; }
			FVector(std::initializer_list<Real>values)
			{
				int i = 0;
				makeZero();
				for (auto iter = values.begin(); i < n && iter != values.end(); ++i, ++iter)
					v[i] = *iter;
			}

			// 一维下标运算符
			Real& operator[](int i) { return v[i]; }
			const Real& operator[](int i) const { return v[i]; }

			// x,y,z,w分量访问方式
			Real& x() { return v[0]; }
			const Real& x() const { return v[0]; }
			Real& y() { return v[1]; }
			const Real& y() const { return v[1]; }
			Real& z() { return v[2]; }
			const Real& z() const { return v[2]; }
			Real& w() { return v[3]; }
			const Real& w() const { return v[3]; }

			// 0(向量)
			FVECTOR& makeZero()
			{
				memset(v, 0, sizeof(v));
				return *this;
			}

			// 1(标准向量)
			FVECTOR& makeIdentity(int i)
			{
				makeZero();
				v[i] = (Real)1;
				return *this;
			}
		};

		// 一元运算符
		FVECTOR_TEMPLATE
			FVECTOR operator-(FVECTOR const& a)
		{
			FVECTOR b;
			for (int i = 0; i < n; ++i)
				b[i] = -a[i];
			return b;
		}

		// 线性运算
		FVECTOR_TEMPLATE
			FVECTOR operator+(FVECTOR a, FVECTOR const& b)
		{
			return a += b;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator+=(FVECTOR& a, FVECTOR const& b)
		{
			for (int i = 0; i < n; ++i)
				a[i] += b[i];
			return a;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator-(FVECTOR a, FVECTOR const& b)
		{
			return a -= b;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator-=(FVECTOR& a, FVECTOR const& b)
		{
			for (int i = 0; i < n; ++i)
				a[i] -= b[i];
			return a;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator*(FVECTOR a, Real k)
		{
			return a *= k;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator*(Real k, FVECTOR a)
		{
			return a *= k;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator*=(FVECTOR& a, Real k)
		{
			for (int i = 0; i < n; ++i)
				a[i] *= k;
			return a;
		}

		FVECTOR_TEMPLATE
			FVECTOR operator/(FVECTOR a, Real k)
		{
			return a /= k;
		}

		FVECTOR_TEMPLATE
			FVECTOR& operator/=(FVECTOR& a, Real k)
		{
			if (k != (Real)0)
				a *= (Real)1 / k;
			else
				a.makeZero();
			return a;
		}

		// 内积(点乘)
		FVECTOR_TEMPLATE
			Real Dot(FVECTOR const& a, FVECTOR const& b)
		{
			Real s = 0;
			for (int i = 0; i < n; ++i)
				s += a[i] * b[i];
			return s;
		}
	}
}

#endif	//_YY_FVECTOR_H_